function getTipsLayer(): UILayer {
	return MainWindow.ins().layerTips;
}

namespace ui {
	const uiLog = false;
	export function isLog(): boolean {
		return isEditor() || uiLog;
	}

	let msglineId = 1;
	export class MsgLine extends eui.Component {
		// lbMsg: eui.Label;
		lbMsg: TextWithImage;

		imgBg: eui.Image;

		rect: eui.Rect;

		msg: string;

		// tw:egret.Tween;
		id = 0; // for debug ...

		color = 0;

		// ml: MsgLines;

		index: number;

		constructor(msg: string, color: number, index: number) {
			super();
			// this.ml = ml;
			this.id = msglineId++;
			this.msg = msg;
			this.color = color;
			this.skinName = 'ui_msgline';
			this.horizontalCenter = 0;
			this.index = index;
			// this.touchEnabled = false;
			// this.touchChildren = false;
		}

		fitTextWidth(): void {
			this.width = this.lbMsg.width;
		}

		oldwidth = 0;

		protected override childrenCreated(): void {
			super.childrenCreated();
			this.oldwidth = this.width;
			this.createTi();
			this.anchorOffsetX = this.width / 2;
			this.anchorOffsetY = this.height / 2;
		}

		protected createTi(): void {
			if (this.color) {
				this.lbMsg.label.textColor = this.color;
			}
			// this.lbMsg.text = this.msg;
			this.lbMsg.setText(this.msg, true);
			if (this.width < this.lbMsg.width) {
				this.width = this.lbMsg.width;
			} else {
				this.width = this.oldwidth;
			}
			if (this.height < this.lbMsg.height) {
				this.height = this.lbMsg.height;
			}
		}

		// moving = false;

		// movey = 0;

		// last = 0;

		moveTo(y: number, last = 1500, wait = 1000): void {
			// this.movey = y;
			// this.last = last;
			// this.moving = true;
			const tw = egret.Tween.get(this);
			tw.to({ scaleX: 0.5, scaleY: 0.5 }, 1)
				.to({ scaleX: 1.5, scaleY: 1.5 }, 100)
				.to({ scaleX: 1, scaleY: 1 }, 100)
				.call(async () => {
					await waitMs(300);
				})
				.to({ y }, last)
				.call(() => {
					// this.moving = false;
					egret.Tween.removeTweens(this);
					const tw2 = egret.Tween.get(this); // 否则改y没有作用！
					tw2.to({ alpha: 0 }, wait).call(() => {
						// this.ml.onFinshed(this);
						safeRemoveFromFather(this);
					});
				});
		}

		// moveDown(h: number): void {
		// 	if (this.moving) {
		// 		egret.Tween.removeTweens(this);
		// 		this.moveTo(this.movey + h, this.last);
		// 	} else {
		// 		this.y += h;
		// 	}
		// }
	}

	class MsgFriend extends eui.Component {
		constructor(
			msg: string,
			color: number,
			// ml: MsgLines,
			index: number,
			param: MsgFriendParam,
		) {
			super();
			this.skinName = 'pnl_favorability_main';
			this.horizontalCenter = 0;
			this.param = param;
		}

		param: MsgFriendParam;

		imgNpc: eui.Image;

		lbNum: eui.Label;

		PLUS = 'plus';

		MINUS = 'minus';

		override childrenCreated(): void {
			super.childrenCreated();

			this.anchorOffsetX = this.width / 2;
			this.anchorOffsetY = this.height / 2;

			this.setMsg();
		}

		setMsg(): void {
			this.currentState = this.param.value > 0 ? this.PLUS : this.MINUS;
			this.imgNpc.source = getIconFull('char', this.param.icon);
			this.lbNum.text =
				this.param.value > 0 ? `+${this.param.value}` : this.param.value.toString();
		}

		moveTo(y: number, last = 1500): void {
			const tw = egret.Tween.get(this);
			tw.to({ scaleX: 0.5, scaleY: 0.5 }, 1)
				.to({ scaleX: 1.5, scaleY: 1.5 }, 100)
				.to({ scaleX: 1, scaleY: 1 }, 100)
				.call(async () => {
					await waitMs(300);
				})
				.to({ y }, last)
				.call(() => {
					egret.Tween.removeTweens(this);
					const tw2 = egret.Tween.get(this);
					tw2.to({ alpha: 0 }, 1000).call(() => {
						safeRemoveFromFather(this);
					});
				});
		}
	}

	class MsgReward extends MsgLine {
		override childrenCreated(): void {
			super.childrenCreated();
		}

		override moveTo(y: number, last = 1500): void {
			const tw = egret.Tween.get(this);
			tw.to({ scaleX: 0.5, scaleY: 0.5 }, 1)
				.to({ scaleX: 1.5, scaleY: 1.5 }, 100)
				.to({ scaleX: 1, scaleY: 1 }, 100)
				.call(async () => {
					await waitMs(300);
				})
				.to({ y }, last)
				.call(() => {
					egret.Tween.removeTweens(this);
					const tw2 = egret.Tween.get(this);
					tw2.to({ alpha: 0 }, 1000).call(() => {
						safeRemoveFromFather(this);
					});
				});
		}
	}

	export class MsgLines extends eui.Component {
		private static instance: MsgLines;

		public static ins(): MsgLines {
			if (!this.instance) {
				this.instance = new MsgLines();
			}
			return this.instance;
		}

		constructor() {
			super();
			const layer = getTipsLayer();
			layer.addChild(this);
			this.horizontalCenter = 0;
			this.touchEnabled = false;
			this.touchChildren = false;
			this.skinName = 'ui_msglines';
		}

		override childrenCreated(): void {
			this.prevY = this.stage.stageHeight / 2;
		}

		prevY = 0;

		index = 1;

		// addMsgline(msg: string, last: number, color: number): void {
		// 	const line = new MsgLine(msg, color, this, this.index++);
		// 	line.y = this.stage.stageHeight / 2;

		// 	this.addChild(line);

		// 	line.moveTo(this.prevY - line.height, last || 3000);

		// 	this.prevY -= line.height;
		// }

		gMessages: eui.Group;

		gRewards: eui.Group;

		async addMsgline(msg: string, last = 3000, color = 0): Promise<void> {
			const line = new MsgLine(msg, color, this.index++);
			this.gMessages.addChild(line);
			line.alpha = 0;
			line.y = Math.floor(this.stage.stageHeight / 2);

			const count = this.gMessages.$children.length;
			await waitMs(500 * (count - 1));

			this.moveMsgLine(line, last || 3000);
			// await waitMs(last || 3000);
			// this.gMessages.removeChildAt(0);
			// safeRemoveFromFather(line);
		}

		async addMsgFriend(
			msg: string,
			last = 3000,
			color = 0,
			friendParam?: MsgFriendParam,
		): Promise<void> {
			const line = new MsgFriend(msg, color, this.index++, friendParam);
			this.gMessages.addChild(line);
			line.alpha = 0;
			line.y = Math.floor(this.stage.stageHeight / 2);
			const count = this.gMessages.$children.length;
			await waitMs(500 * (count - 1));
			this.moveMsgFriend(line);
			// await waitMs(3500);
			// this.gMessages.removeChildAt(0);
		}

		async addMsgReward(
			msg: string,
			last = 3000,
			color = 0,
			aniDir?: string,
			aniX = 0,
			aniY = 0,
		): Promise<void> {
			const line = new MsgReward(msg, color, this.index++);
			if (aniDir) {
				const gAni = new eui.Group();
				line.addChild(gAni);
				ui.PlaySimpleAni.ins().Play(aniDir, gAni, -1, aniX, aniY);
			}
			this.gRewards.addChild(line);
			line.alpha = 0;
			line.y = Math.floor((this.stage.stageHeight / 4) * 3) + line.height;
			const count = this.gRewards.$children.length;
			await waitMs(500 * (count - 1));
			this.moveMsgReward(line);
			// await waitMs(3500);
			// this.gRewards.removeChildAt(0);
		}

		moveMsgLine(line: MsgLine, wait: number): void {
			line.alpha = 1;
			line.moveTo(this.stage.stageHeight / 4, 2000, wait);
		}

		moveMsgFriend(line: MsgFriend): void {
			line.alpha = 1;
			line.moveTo(this.stage.stageHeight / 4, 2000);
		}

		moveMsgReward(line: MsgReward): void {
			line.alpha = 1;
			line.moveTo((this.stage.stageHeight / 5) * 3, 2000);
		}

		onFinshed(line: MsgLine): void {
			safeRemoveFromFather(line);
			// this.prevY += line.height;
			// for (const c of this.$children) {
			// 	// 并不应该所有的都movedown，大家的生命周期不一样，只有在其之上的才需要，
			// 	if (c instanceof MsgLine) {
			// 		if (c.index > line.index) {
			// 			c.moveDown(line.height);
			// 		}
			// 	}
			// }
		}

		childrenHeight(): number {
			let h = 0;
			for (const c of this.$children) {
				h += c.height;
			}
			return h;
		}
	}

	function msglineRaw(msg: string, last: number, color = 0): void {
		const layer = getTipsLayer();
		if (!layer) {
			return;
		}
		MsgLines.ins().addMsgline(msg, last, color);
	}

	function msglineFriend(
		msg: string,
		last: number,
		color = 0,
		friendParam: MsgFriendParam,
	): void {
		MsgLines.ins().addMsgFriend(msg, last, color, friendParam);
	}

	function msglineReward(
		msg: string,
		last: number,
		color = 0,
		aniDir?: string,
		aniX?: number,
		aniY?: number,
	): void {
		MsgLines.ins().addMsgReward(msg, last, color, aniDir, aniX, aniY);
	}

	function simpleString(arg: any): string {
		try {
			if (Array.isArray(arg) || typeof arg === 'object') {
				return JSON.stringify(arg);
			}
		} catch (e) {
			if (Array.isArray(arg)) {
				return 'array';
			}
			if (typeof arg === 'object') {
				// return JSON.stringify(arg);
				return 'object';
			}
		}
		return String(arg);
	}

	export function msgDebug(...args: any[]): void {
		if (!isDebug()) {
			console.log('msgDev', ...args);
			return;
		}
		msglog(...args);
	}

	export function msglog(...args: any[]): void {
		_msglogCheck(true, ...args);
	}

	function _msglogCheck(check: boolean, ...args: any[]): void {
		if (check && !isLog()) {
			console.log('msgLogCheck', ...args);
			return;
		}
		_msglogTimeColor(5000, 0, ...args);
	}
	function _msgerrorCheck(check: boolean, ...args: any[]): void {
		if (check && !isLog()) {
			console.log('msgerrorCheck', ...args);
			return;
		}
		_msglogTimeColor(10000, 0xff0000, ...args);
	}

	function _msglogTimeColor(time: number, color: number, ...args: any[]): void {
		console.log('_msglogTimeColor', ...args);
		const ss = [];
		for (let i = 0; i < args.length; i++) {
			ss.push(simpleString(args[i]));
		}
		const s = ss.join(' ');
		msglineRaw(s, time, color);
	}

	export function log(...args: any[]): void {
		_msglogCheck(true, ...args);
	}

	export function tips(...args: any[]): void {
		_msglogCheck(false, ...args);
	}

	export function tellme(...args: any[]): void {
		_msglogCheck(false, ...args);
	}

	export function msgErrorEnum(error: ErrorEnum, ...args: any[]): void {
		if (error === ErrorEnum.ErrorOk) {
			return;
		}
		const str = getErrorEnumString(error);
		if (str) {
			const info = getErrorTipsInfo(str);
			if (info) {
				_msgerrorCheck(false, info.Tip1, ...args);
				return;
			}
		}
		_msgerrorCheck(true, str || error, ...args);
	}

	export function msgwarn(...args: any[]): void {
		_msgerrorCheck(true, ...args);
	}

	export function msgerror(...args: any[]): void {
		_msgerrorCheck(true, ...args);
	}

	// yujiang， 按照道理不能调用这个！都应该改为msgid
	export function msgline(msg: string, last = 3000, color = 0): void {
		msg = clientToLocal(msg);
		msglineRaw(msg, last, color);
	}

	export function msgfriend(
		msg: string,
		last = 3000,
		color = 0,
		friendParam: MsgFriendParam,
	): void {
		msg = clientToLocal(msg);
		msglineFriend(msg, last, color, friendParam);
	}

	export function msgreward(
		msg: string,
		last = 3000,
		color = 0,
		aniDir?: string,
		aniX?: number,
		aniY?: number,
	): void {
		msg = clientToLocal(msg);
		msglineReward(msg, last, color, aniDir, aniX, aniY);
	}

	export function msgid(id: number, ..._args: any[]): void {
		const info = getMsgInfo(id);
		if (info) {
			const text = info.Name.formats(_args);
			msgline(text);
		} else {
			msgerror('not find msg info', id);
		}
	}
}

const msgThrottle = dt.throttle(3000, false, (msg: string) => {
	ui.msgline(msg);
});
